﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Barbar.UrlGuard.Dal;
using Barbar.UrlGuard.Dal.Persist;
using System.Globalization;
using Barbar.UrlGuard.BL;

namespace Barbar.UrlGuard.Controls {
  public class ChainTreeView : TreeView, ILocalizable {
    private TreeNode m_LastClickNode;
    private TreeContextMenu m_TreeContextMenu;
    private UrlContextMenu m_UrlContextMenu; 
    private ChainContextMenu m_ChainContextMenu;

    public ChainTreeView() {
      m_ChainContextMenu = new ChainContextMenu();
      m_UrlContextMenu = new UrlContextMenu();
      m_TreeContextMenu = new TreeContextMenu();

      ContextMenu = m_TreeContextMenu;

      m_ChainContextMenu.Command += new EventHandler<ChainContextMenuEventArgs>(ChainContextMenu_Command);
      m_UrlContextMenu.Command += new EventHandler<UrlContextMenuEventArgs>(UrlContextMenu_Command);
      m_TreeContextMenu.Command += new EventHandler(TreeContextMenu_Command);
      MouseClick += new MouseEventHandler(ChainTreeView_MouseClick);
    }

    public void RedrawTree() {
      SuspendLayout();
      Nodes.Clear();
      IDataContextHolder holder = ServiceLocator.Instance.Resolve<IDataContextHolder>();
      foreach (MonitoringChain chain in holder.Context.Chains) {
        TreeNode node = new TreeNode(chain.Name);
        node.Tag = chain;
        node.ContextMenu = m_ChainContextMenu;
        MonitoringEntryStatus overallStatus = MonitoringEntryStatus.None;

        foreach (MonitoringEntry monitoringEntry in chain.Entries) {
          TreeNode child = new TreeNode(string.Format(CultureInfo.InvariantCulture, "{0} Code:{1}, Time[ms]:{2}, Accessed:{3} minutes ago", monitoringEntry.Url, monitoringEntry.LastStatusCode, monitoringEntry.LastRequestLength, monitoringEntry.LastCheckDate.HasValue ? DateTime.Now.Subtract(monitoringEntry.LastCheckDate.Value).Minutes : 0));
          if (monitoringEntry.Status.Value == MonitoringEntryStatus.OK.Value && overallStatus.Value == MonitoringEntryStatus.None.Value) {
            overallStatus = MonitoringEntryStatus.OK;
          }
          if (monitoringEntry.Status.Value == MonitoringEntryStatus.Error.Value) {
            overallStatus = MonitoringEntryStatus.Error;
          }
          child.BackColor = monitoringEntry.Status.StatusColor;
          child.ContextMenu = m_UrlContextMenu;
          child.Tag = monitoringEntry;
          node.Nodes.Add(child);
        }
        node.BackColor = overallStatus.StatusColor;
        Nodes.Add(node);
      }
      ExpandAll();
      ResumeLayout();
    }

    void ChainTreeView_MouseClick(object sender, MouseEventArgs e) {
      if (e.Button == MouseButtons.Right) {
        m_LastClickNode = GetNodeAt(e.X, e.Y);
      }
    }

    private void PersistAndRedraw() {
      IDataContextHolder dataContextHolder = ServiceLocator.Instance.Resolve<IDataContextHolder>();
      dataContextHolder.Persist();
      RedrawTree();
    }

    public void AddChain() {
      FormAddOrEditChainDialog addOrEditChainDialog = new FormAddOrEditChainDialog();
      IInjectorUtility utility = ServiceLocator.Instance.Resolve<IInjectorUtility>();
      utility.LoadData<MonitoringChain>(null, addOrEditChainDialog);
      DialogResult result = addOrEditChainDialog.ShowDialog();
      if (result == DialogResult.OK) {
        MonitoringChain chain = new MonitoringChain();
        utility.SaveData<MonitoringChain>(chain, addOrEditChainDialog);
        
        IDataContextHolder dataContextHolder = ServiceLocator.Instance.Resolve<IDataContextHolder>();
        dataContextHolder.Context.Chains.Add(chain);
        PersistAndRedraw();
      }
    }

    public void EditChain(MonitoringChain chain) {
      if (chain == null)
        throw new ArgumentNullException("chain");

      FormAddOrEditChainDialog addOrEditChainDialog = new FormAddOrEditChainDialog();
      IInjectorUtility utility = ServiceLocator.Instance.Resolve<IInjectorUtility>();
      utility.LoadData<MonitoringChain>(chain, addOrEditChainDialog);

      DialogResult result = addOrEditChainDialog.ShowDialog();
      if (result == DialogResult.OK) {
        utility.SaveData<MonitoringChain>(chain, addOrEditChainDialog);
        PersistAndRedraw();
      }
    }

    public void RemoveChain(MonitoringChain chain) {
      if (chain == null)
        throw new ArgumentNullException("chain");

      IDataContextHolder dataContextHolder = ServiceLocator.Instance.Resolve<IDataContextHolder>();
      dataContextHolder.Context.Chains.Remove(chain);
      PersistAndRedraw();
    }

    public MonitoringChain SelectedChain {
      get {
        if (SelectedNode == null)
          return null;

        object tag = SelectedNode.Tag;
        MonitoringChain chain = tag as MonitoringChain;
        if (chain != null)
          return chain;

        return (MonitoringChain)SelectedNode.Parent.Tag;
      }
    }

    public MonitoringEntry SelectedEntry {
      get {
        if (SelectedNode == null)
          return null;

        return (SelectedNode.Tag as MonitoringEntry);
      }
    }

    public void AddUrl(MonitoringChain chain) {
      if (chain == null)
        throw new ArgumentNullException("chain");

      IInjectorUtility utility = ServiceLocator.Instance.Resolve<IInjectorUtility>();
      FormAddOrEditUrlDialog addOrEditUrlDialog = new FormAddOrEditUrlDialog();
      utility.LoadData<MonitoringEntry>(null, addOrEditUrlDialog);
      DialogResult result = addOrEditUrlDialog.ShowDialog();
      if (result == DialogResult.OK) {
        MonitoringEntry entry = new MonitoringEntry();
        utility.SaveData<MonitoringEntry>(entry, addOrEditUrlDialog);
        chain.Entries.Add(entry);
        PersistAndRedraw();
      }
    }

    public void EditUrl(MonitoringEntry entry) {
      if (entry == null)
        throw new ArgumentNullException("entry");

      IInjectorUtility utility = ServiceLocator.Instance.Resolve<IInjectorUtility>();
      FormAddOrEditUrlDialog addOrEditUrlDialog = new FormAddOrEditUrlDialog();
      utility.LoadData<MonitoringEntry>(entry, addOrEditUrlDialog);

      DialogResult result = addOrEditUrlDialog.ShowDialog();
      if (result == DialogResult.OK) {
        utility.SaveData<MonitoringEntry>(entry, addOrEditUrlDialog);
        PersistAndRedraw();
      }
    }

    public void RemoveUrl(MonitoringEntry entry, MonitoringChain chain) {
      if (entry == null)
        throw new ArgumentNullException("entry");

      if (chain == null)
        throw new ArgumentNullException("chain");

      chain.Entries.Remove(entry);
      PersistAndRedraw();
    }

    private void ShowGraph(MonitoringEntry entry) {
      if (entry == null)
        throw new ArgumentNullException("entry");

      IGraphProvider graphProvider = ServiceLocator.Instance.Resolve<IGraphProvider>();
      graphProvider.ShowGraph(entry.Uid);
    }

    private void TreeContextMenu_Command(object sender, EventArgs e) {
      AddChain();
    }

    private void UrlContextMenu_Command(object sender, UrlContextMenuEventArgs e) {
      switch (e.Command) {
        case UrlContextMenuCommand.AddUrl:
          if (m_LastClickNode != null && m_LastClickNode.Parent != null) {
            MonitoringChain chain = (MonitoringChain)m_LastClickNode.Parent.Tag;
            if (chain != null) {
              AddUrl(chain);
            }
          }
          break;
        case UrlContextMenuCommand.EditUrl:
          if (m_LastClickNode != null && m_LastClickNode.Parent != null) {
            MonitoringEntry entry = (MonitoringEntry)m_LastClickNode.Tag;
            EditUrl(entry);
          }
          break;
        case UrlContextMenuCommand.RemoveUrl:
          if (m_LastClickNode != null && m_LastClickNode.Parent != null) {
            MonitoringChain chain = (MonitoringChain)m_LastClickNode.Parent.Tag;
            MonitoringEntry entry = (MonitoringEntry)m_LastClickNode.Tag;
            RemoveUrl(entry, chain);
          }
          break;
        case UrlContextMenuCommand.ShowHistory:
          if (m_LastClickNode != null && m_LastClickNode.Parent != null) {
            MonitoringEntry entry = (MonitoringEntry)m_LastClickNode.Tag;
            if (entry != null) {
              FormHistory formHistory = new FormHistory(entry.Uid, entry.Url);
              formHistory.ShowDialog(this);
            }
          }
          break;
        case UrlContextMenuCommand.ShowHistoryGraph:
          if (m_LastClickNode != null && m_LastClickNode.Parent != null) {
            MonitoringEntry entry = (MonitoringEntry)m_LastClickNode.Tag;
            if (entry != null) {
              ShowGraph(entry);
            }
          }
          break;
        default:
          throw new NotImplementedException();
      }
    }

    private void ChainContextMenu_Command(object sender, ChainContextMenuEventArgs e) {
      switch (e.Command) {
        case ChainContextMenuCommand.AddChain:
          AddChain();
          break;
        case ChainContextMenuCommand.EditChain:
          if (m_LastClickNode != null) {
            MonitoringChain chain = (MonitoringChain)m_LastClickNode.Tag;
            EditChain(chain);
          }
          break;
        case ChainContextMenuCommand.RemoveChain:
          if (m_LastClickNode != null) {
            MonitoringChain chain = (MonitoringChain)m_LastClickNode.Tag;
            RemoveChain(chain);
          }
          break;
        case ChainContextMenuCommand.AddUrl:
          if (m_LastClickNode != null) {
            MonitoringChain chain = (MonitoringChain)m_LastClickNode.Tag;
            if (chain != null) {
              AddUrl(chain);
            }
          }
          break;
        default:
          throw new NotImplementedException();
      }
    }

    #region ILocalizable Members

    public void Localize(ILocalizator localizator) {
      if (localizator == null)
        throw new ArgumentNullException("localizatior");

      m_UrlContextMenu.Localize(localizator);
      m_ChainContextMenu.Localize(localizator);
      m_TreeContextMenu.Localize(localizator);
    }

    #endregion
  }
}
